package utwente.hmi.touchmol.elements;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;

import org.jmol.adapter.smarter.SmarterJmolAdapter;
import org.jmol.api.JmolAdapter;
import org.jmol.viewer.Viewer;
import org.jmol.popup.JmolPopup;
import org.jmol.api.JmolStatusListener;
//import org.jmol.g3d.*;

/**
 * The MolPanel is the panel that integrates Jmol into TouchMol.
 * @author Jeroen Logtenberg, original source by Wim Fikkert
 */
public class MolPanel extends JPanel {
	private static final long serialVersionUID = -3667521705814167927L;
	public static int FORWARDS = 1;
	public static int BACKWARDS = -1;
	public static double PI2 = Math.PI * 2;

	public Viewer viewer;
	private JmolAdapter adapter;
	public JmolPopup popup ;

	private Dimension currentSize;
	private Rectangle rectClip;

	private boolean showAxes = false;
	private float rotateX = 0.0f, rotateY = 0.0f, rotateZ = 0.0f;
	public int zoom = 100;
	private long lastZoomUpdate = 0;
	private boolean stereoToggle = false;

	public MolPanel(int myWidth, int myHeight) {

		currentSize = new Dimension(myWidth, myHeight);
		rectClip = new Rectangle(currentSize);

		
		setPreferredSize(currentSize);
		setBackground(Color.BLACK);

		adapter = new SmarterJmolAdapter();
		viewer = new Viewer(this, adapter); // JmolViewer.allocateViewer
		popup = JmolPopup.newJmolPopup(viewer,true,null,true);
        // this is important to make Jmol thread -safe !!
        viewer.evalString("set scriptQueue on;");

		viewer.openStringInline("3\nwater\nO  0.0 0.0 0.0\nH  0.76923955 -0.59357141 0.0\nH -0.76923955 -0.59357141 0.0\n");

		repaint();
	}

	public void loadPDB(String filename) {
		viewer.evalString("load PDB " + filename);
	}

	public void displayText(String text){
		evalString("set echo bottom center; font echo 22 serif; color echo white");
		evalString("echo \"Echo test\"");
	}
	
	public void rotate(double x, double y, double z) {

		rotateX = (float) x;
		rotateY = (float) y;
		rotateZ = (float) z;

		viewer.evalString("rotate x " + rotateX + "; rotate y " + rotateY
				+ "; rotate z " + rotateZ + ";");
	}

	/**
	 * Zoom in/out on molecule. Forces minimal of 35 milliseconds between zoom
	 * events
	 * 
	 * @param diff
	 */
	public void zoom(int diff) {
		if (lastZoomUpdate == 0) {// do not update yet!
			lastZoomUpdate = System.currentTimeMillis();
		} else if (System.currentTimeMillis() - lastZoomUpdate > 35) {
			zoom += diff;
			lastZoomUpdate = 0;
			if (zoom < 10)
				zoom = 10;
			else if (zoom > 2000)
				zoom = 2000;
			viewer.evalString("zoom " + zoom); // instant zoom to
		}
	}

	public void toggleAxes() {
		showAxes = !showAxes;
		if (showAxes)
			evalString("axes MOLECULAR; axes DOTTED; axes ON;");
		else
			evalString("axes OFF");
	}

	public void toggleStereo() {
		if (!stereoToggle)
			evalString("stereo REDCYAN");
		else
			evalString("stereo OFF");
		stereoToggle = !stereoToggle;
	}

	public void evalString(String eval) {
		System.out.print("EVAL: " + eval + "\n");
		viewer.evalString(eval);
	}

	public void openStringInline(String eval) {
		viewer.openStringInline(eval);
	}

	public void openFile(String eval) {
		viewer.openFile(eval);
	}

	public void restoreScreenshot(Screenshot screenshot) {
		if (screenshot == null) {
			System.out.println("screenshot not present");
			return;
		}
		viewer.evalString(screenshot.script);
		zoom = screenshot.zoom;
		lastZoomUpdate = 0;
	}

	/**
	 * Makes and returns screenshot of this panel
	 * 
	 * @return BufferedImage with size equaling this panel, containing the
	 *         displayed molecule
	 * @return BufferedImage with 0x0 size when not able to capture a
	 *         screenshot!
	 */
	public BufferedImage getScreenshot() {
		BufferedImage screenshot;
		try {
			Point p = this.getLocationOnScreen();
			Rectangle r = this.getBounds();
			r.setLocation(p);
			screenshot = new Robot().createScreenCapture(r);
			Graphics2D g = (Graphics2D) screenshot.getGraphics();
			g.setColor(Color.BLUE);
			g.fillRect(0, 0, 5, screenshot.getHeight());
			g.fillRect(0, 0, screenshot.getWidth(), 5);
			g.fillRect(screenshot.getWidth() - 5, 0, screenshot.getWidth(),
					screenshot.getHeight());
			g.fillRect(0, screenshot.getHeight() - 5, screenshot.getWidth(),
					screenshot.getHeight());

			g.dispose();
		} catch (AWTException ex) {
			Logger.getLogger(MolPanel.class.getName()).log(Level.SEVERE,
					"Could not make screenshot", ex);
			screenshot = new BufferedImage(0, 0, BufferedImage.TYPE_BYTE_BINARY);
		}
		return screenshot;
	}
	
	/**
	 * This method checks if the molpanel is touched at a certain location.
	 * @param location The point on the screen where the touch has occurred.
	 * @return If the touch has occurred inside the panel.
	 */
	public boolean panelTouched(Point location){
		Rectangle r = this.getBounds();
		Point p = this.getLocationOnScreen();
		r.setLocation(p);
		return r.contains(location);
	}

	@Override
	public void paint(Graphics g) {
		viewer.renderScreenImage(g, currentSize, rectClip);
	}
	
	/** Add a JmolStatus listener to Jmol
     * 
     * @see TouchMolGUI
     * 
     * @param listener
     */
    public void addJmolStatusListener(JmolStatusListener listener) {
        viewer.setJmolStatusListener(listener);   
   }
    
    /**  
     * remove the listeners from Jmol again.
     */
    public void clearListeners(){
        
        viewer.setJmolStatusListener(null);
        
    }

}